Skip to content

ci(docker): assert the SQL drivers are in the published runtime image - #16080

Merged
os-steve merged 1 commit into
mainfrom
claude/issue-14701-image-driver-probe
Sep 6, 2026
Merged

ci(docker): assert the SQL drivers are in the published runtime image#16080
os-steve merged 1 commit into
mainfrom
claude/issue-14701-image-driver-probe

Conversation

@os-steve

@os-steve os-steve commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

Fixes #14701

Adds one docker run to the existing amd64 smoke step in .github/workflows/docker-publish.yml, asserting that pg and mysql2 are actually in the built image.

Why this line and not the in-repo pin

check:docs-image-tag compares docker/Dockerfile's install line against docker/README.md's published driver table. Both files would still agree if the drivers vanished from the built image, so that gate cannot see this.

The regression is not hypothetical. docker/Dockerfile:46-52 records it happening — verified verbatim at this branch's base c463d03e0: @objectstack/driver-sql declares pg / mysql2 / tedious as optional peer dependencies, npm 7+ skips optional peers, and the resulting tree "died at boot on Cannot find module 'pg'". The probe guards the exact regression the install line exists to prevent.

The proposed one-liner does not work — it is a constant red

The card suggested:

docker run --rm "$IMAGE:$VERSION" node -e "require('pg'); require('mysql2')"

Measured, that spelling fails identically on an image that has the drivers and one that does not, so it never discriminates and would have broken every release:

spelling image WITH drivers image WITHOUT drivers
as proposed (cwd /srv/app) exit=1 exit=1
-w /usr/local/lib/node_modules exit=0 exit=1

Cause: npm install -g writes to /usr/local/lib/node_modules, which is not on require()'s search path from the image's WORKDIR (/srv/app). Node's global folders are $PREFIX/lib/node, and the node:22-slim base sets no NODE_PATH (confirmed against the upstream nodejs/docker-node Dockerfile for 22/bookworm-slim, which sets only NODE_VERSION and YARN_VERSION).

Resolving from inside the global tree is also how the real boot path resolves them: driver-sql lives in that tree, so it walks up into /usr/local/lib/node_modules and finds pg. The shipped probe reproduces that resolution rather than inventing a second one. The -w flag is load-bearing and the step comment says so, because the obvious "simplification" is the broken form.

Reverse reading — taken, both directions

Required as binding by triage. The line as committed was extracted verbatim from the YAML and run under Actions' shell (bash -e):

  • image with the drivers: exit=0
  • image without the drivers: exit=1, Error: Cannot find module 'pg'
  • also confirmed under a non-root user, matching the image's USER node: exit=0 / exit=1

Vehicle, stated honestly: the two images are purpose-built locally, not the real published image. Container blob reads are refused by this environment's egress policy — docker pull of both node:22-slim and ghcr.io/objectstack-ai/objectstack resolves the manifest and then gets Forbidden on the blob CDN — so the real image cannot be pulled or built here. The vehicles replicate the layout that decides the outcome exactly: node at /usr/local/bin, globals at /usr/local/lib/node_modules, WORKDIR /srv/app, no NODE_PATH. The outcome is a property of node's resolution algorithm over that layout, which is reproduced faithfully. What is not covered here is the real base image and the real npm install -g; CI exercises those on the first run.

Scope

  • No boot test — require() needs no artifact and no database, so the step stays on the right side of the line the existing comment draws.
  • check:docs-image-tag is untouched; it asserts something different and still passes.
  • CI-workflow-only, publishes nothing: skip-changeset.

Generated by Claude Code

The smoke step proved the CLI resolved but nothing asserted that `pg` and
`mysql2` -- which docker/Dockerfile installs and docker/README.md publishes
as a maintained promise -- are actually in the built image. The in-repo
`check:docs-image-tag` pin cannot see that: it compares the install line
against the published table, and both would still agree if the drivers
vanished from the image.

The probe resolves from inside the global tree (`-w`), which is both how the
real boot path resolves the drivers and the only spelling that discriminates:
`npm install -g` writes to /usr/local/lib/node_modules, which is not on
`require()`'s search path from the image's WORKDIR (/srv/app), and the
node:22-slim base sets no NODE_PATH.

Verified in both directions against purpose-built images before landing:
green with the drivers present, red (`Cannot find module 'pg'`) without.

Claude-Session: https://claude.ai/code/session_01PU9zBGbH2s2ZtxSyu963M3
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added the size/s label Sep 5, 2026
@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 5, 2026
@github-actions github-actions Bot added the ci/cd label Sep 5, 2026
@os-steve
os-steve marked this pull request as ready for review September 6, 2026 00:12
@os-steve
os-steve enabled auto-merge September 6, 2026 00:12
@os-steve
os-steve added this pull request to the merge queue Sep 6, 2026
Merged via the queue into main with commit 2648774 Sep 6, 2026
31 checks passed
@os-steve
os-steve deleted the claude/issue-14701-image-driver-probe branch September 6, 2026 01:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

docker-publish.yml smoke step proves the CLI resolved but not that the image's SQL drivers did

1 participant